import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 用于微服务自动获取当前认证用户信息的自动配置。
 * 当前配置类和Advisor上添加@Role(BeanDefinition.ROLE_INFRASTRUCTURE)，是为了避免进行代理检查，导致控制台出现警告（对程序正常运行无影响）
 */
@AutoConfiguration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class GlobalAutoConfiguration implements WebMvcConfigurer {
    private ApplicationContext applicationContext;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void addInterceptors(@NonNull InterceptorRegistry registry) {
        try {
            AuthHandlerInterceptor interceptor = applicationContext.getBean(AuthHandlerInterceptor.class);
            registry.addInterceptor(interceptor);
        } catch (BeansException e) {
            //do nothing...
        }
    }

    /**
     * 创建拦截器，获取当前认证用户信息
     *
     * @return 拦截器实例
     */
    @ConditionalOnProperty(prefix = "stmall.services.auto-get-auth", name = "enabled", havingValue = "true", matchIfMissing = true)
    @ConditionalOnMissingBean(name = "authHandlerInterceptor")
    @Bean
    public AuthHandlerInterceptor authHandlerInterceptor() {
        return new AuthHandlerInterceptor();
    }

    /**
     * 创建切面，自动为审计类型的模型类，添加创建时间和更新时间，以及创建人、更新人
     * 注意：必须必须添加@EnableAspectJAutoProxy注解，否则Advisor不生效
     *
     * @return 切面实例
     */
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    public Advisor autoAuditAspect() {
        AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
        //execution表达式默认仅匹配指定类中直接声明的方法。若方法定义在父类或接口中，但未被实现类重写，则不会被识别
        pc.setExpression("execution(* com.agrm.*.service.impl.*.*(..))");
        return new DefaultPointcutAdvisor(pc, new AutoAuditMethodInterceptor());
    }
}
